package cn.buk.tms.dao;

import cn.buk.common.sc.Page;
import cn.buk.tms.entity.order.flight.FlightChangeOrder_;
import cn.buk.tms.factory.OperationLogFactory;
import cn.buk.tms.sc.SearchFlightOrderCriteria;
import cn.buk.common.util.DateUtil;
import cn.buk.tms.entity.misc.OperationLog;
import cn.buk.tms.entity.order.OrderAttachment;
import cn.buk.tms.entity.misc.PaymentMethod;
import cn.buk.tms.entity.misc.Supplier;
import cn.buk.tms.entity.order.flight.FlightChangeOrder;
import cn.buk.tms.entity.order.flight.FlightChangeOrderDetail;
import jakarta.persistence.criteria.*;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Repository;

import jakarta.transaction.Transactional;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import static cn.buk.tms.entity.order.flight.FlightChangeOrder.*;
import static cn.buk.tms.common.constant.TmsOrderConstant.OPERATING_OBJECT_FLIGHT_CHANGE_ORDER;
import static cn.buk.tms.common.constant.TmsOrderConstant.ORDER_TYPE_FLIGHT_CHANGE;

/**
 * @author yfdai
 */
@Repository
@Transactional
public class FlightChangeOrderDaoImpl extends AbstractDao implements FlightChangeOrderDao {

  private OperationLog createFlightChangeOrderLog(int enterpriseId, String username,
      int refundOrderId, String remark) {
    OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
    log.setEnterpriseId(enterpriseId);
    log.setOperator(username);
    log.setOrderId(refundOrderId);
    log.setContent(remark);

    return log;
  }

  @Override
  public int createFlightChangeOrder(FlightChangeOrder info) {
    em.persist(info);
    em.flush();

    int retCode = info.getId();
    if (retCode > 0) {
      OperationLog log = createFlightChangeOrderLog(info.getEnterpriseId(), info.getOperator(), info.getId(), "创建改签单");
      em.persist(log);
    }

    return retCode;
  }

  private List<Predicate> buildPredicates_searchFlightChangeOrder(CriteriaBuilder cb, Root<FlightChangeOrder> root,
                                                                  int enterpriseId,
                                                                  SearchFlightOrderCriteria sc, List<Integer> allowedCustomerIds) {
    List<Predicate> predicates = new ArrayList<>();

    Predicate predicate = cb.conjunction();
    predicates.add(predicate);

    predicate = cb.equal(root.get(FlightChangeOrder_.enterpriseId), enterpriseId);
    predicates.add(predicate);

    if (sc.getCustomerId() == 0) {
      // 散客
      predicate = cb.equal(root.get(FlightChangeOrder_.customerType), 0);
      predicates.add(predicate);
    } else if (sc.getCustomerId() > 0) {
      // 企业
      predicate = cb.equal(root.get(FlightChangeOrder_.customer), sc.getCustomerId());
      predicates.add(predicate);
    }

    if (sc.getBalCode() != null && sc.getTicketNo() != null) {
      if (sc.getBalCode().length() == 3 && sc.getTicketNo().length() == 10) {
        predicate = cb.equal(root.get(FlightChangeOrder_.balanceCode), sc.getBalCode());
        predicates.add(predicate);

        predicate = cb.equal(root.get(FlightChangeOrder_.ticketNo), sc.getTicketNo());
        predicates.add(predicate);
      }
    }

    if (sc.getIntlTicket() > -1) {
      predicate = cb.equal(root.get(FlightChangeOrder_.intlTicket), sc.getIntlTicket());
      predicates.add(predicate);
    }

    if (sc.getName() != null && sc.getName().trim().length() > 0) {
      predicate = cb.like(root.get(FlightChangeOrder_.psgName), "%" + sc.getName().trim() + "%");
      predicates.add(predicate);
    }

    if (sc.getIdno() != null && sc.getIdno().trim().length() > 0) {
      predicate = cb.like(root.get(FlightChangeOrder_.idNo), "%" + sc.getIdno().trim() + "%");
      predicates.add(predicate);
    }

    if (sc.getStatus() > -1) {
      predicate = cb.equal(root.get(FlightChangeOrder_.status), sc.getStatus());
      predicates.add(predicate);
    }

    if (sc.getPnrNo() != null && sc.getPnrNo().trim().length() > 0) {
      predicate = cb.equal(root.get(FlightChangeOrder_.oldPnrNo), sc.getPnrNo().trim());
      predicate = cb.or(predicate, cb.equal(root.get(FlightChangeOrder_.newPnrNo), sc.getPnrNo().trim()));
      predicates.add(predicate);
    }

    if (sc.getTicketNo().length() > 0) {
      String temp = sc.getTicketNo().trim();
      if (temp.length() >= 10) {
        temp = temp.substring(temp.length() - 10);

        predicate = cb.equal(root.get(FlightChangeOrder_.ticketNo), temp);
        predicate = cb.or(predicate, cb.like(root.get(FlightChangeOrder_.newTicketNo), "%" + temp + "%"));
      } else {
        predicate = cb.like(root.get(FlightChangeOrder_.ticketNo), "%" + temp + "%");
        predicate = cb.or(predicate, cb.like(root.get(FlightChangeOrder_.newTicketNo), "%" + temp + "%"));

      }
      predicates.add(predicate);
    }

    if (sc.getBeginDate() != null) {
      predicate = cb.greaterThanOrEqualTo(root.get(FlightChangeOrder_.createTime), sc.getBeginDate());
      predicates.add(predicate);
    }

    if (sc.getEndDate() != null) {
      predicate = cb.lessThanOrEqualTo(root.get(FlightChangeOrder_.createTime),
              DateUtil.addDays(sc.getEndDate(), 1));
      predicates.add(predicate);
    }

    if (sc.getOrderNo().length() > 0) {
      predicate = cb.equal(root.get(FlightChangeOrder_.orderNo), sc.getOrderNo());
      predicates.add(predicate);
    }

    if (sc.getChangeOrderNo().length() > 0) {
      predicate = cb.equal(root.get(FlightChangeOrder_.changeOrderNo), sc.getChangeOrderNo());
      predicates.add(predicate);
    }

    if (sc.getOp1() != null && sc.getOp1().trim().length() > 0) {
      predicate = cb.equal(root.get(FlightChangeOrder_.operator), sc.getOp1());
      predicates.add(predicate);
    }

    if (allowedCustomerIds != null && !allowedCustomerIds.isEmpty()) {
      // 只允许查看指定的企业客户的订单
      predicate = cb.in(root.get(FlightChangeOrder_.customer).get("id")).value(allowedCustomerIds);
      predicates.add(predicate);
    }

    return predicates;
  }

  @Override
  public List<FlightChangeOrder> searchFlightChangeOrder(int enterpriseId,
                                                         SearchFlightOrderCriteria sc, List<Integer> allowedCustomerIds) {
    List<FlightChangeOrder> results = null;

    CriteriaBuilder cb = em.getCriteriaBuilder();
    CriteriaQuery<FlightChangeOrder> cq = cb.createQuery(FlightChangeOrder.class);
    Root<FlightChangeOrder> root = cq.from(FlightChangeOrder.class);
    root.alias("o");


    var predicates0 = buildPredicates_searchFlightChangeOrder(cb, root, enterpriseId, sc, allowedCustomerIds);

    //计算根据条件查询得出的数据总数
    CriteriaQuery<Long> countQuery = cb.createQuery(Long.class);
    Root<FlightChangeOrder> countRoot = countQuery.from(FlightChangeOrder.class);
    countRoot.alias("o");

    var predicates1 = buildPredicates_searchFlightChangeOrder(cb, countRoot, enterpriseId, sc, allowedCustomerIds);

    countQuery.select(cb.count(countRoot))
        .where(predicates1.toArray(new Predicate[predicates1.size()]));
    Long count = em.createQuery(countQuery).getSingleResult();

    int maxResults = count.intValue();
    if (maxResults > 0) {
      cq.where(predicates0.toArray(new Predicate[predicates0.size()]));
      List<Order> orderByes = new ArrayList<>();
      orderByes.add(cb.desc(root.get("id")));

      cq.orderBy(orderByes);

      Page page = sc.getPage();
      page.setRowCount(maxResults);
      int i = (page.getPageNo() - 1) * page.getPageSize();

      if (i < 0) {
        i = 0;
      }

      results = em.createQuery(cq)
          .setFirstResult(i)
          .setMaxResults(page.getPageSize()).getResultList();
    }

    if (results == null) {
      results = new ArrayList<>();
    }

    return results;
  }

  @Override
  public FlightChangeOrder getFlightChangeOrderDetail(int id) {
    FlightChangeOrder o = em.find(FlightChangeOrder.class, id);
    if (o != null) {
      em.refresh(o);
    }
    return o;
  }

  @Override
  public List<OperationLog> searchFlightChangeOrderHistory(int enterpriseId, int id) {
    return searchOrderHistory(enterpriseId, OPERATING_OBJECT_FLIGHT_CHANGE_ORDER, id);
  }

  @Override
  public int processFlightChangeOrder(int enterpriseId, String username, int orderId) {
    int retCode = em.createQuery(
        "update FlightChangeOrder o set " +
                "o.status = :newStatus, o.lastUpdate = :lastUpdate, o.ticketer = :ticketer " +
            "where " +
            "o.id = :id and o.enterpriseId = :enterpriseId and o.status = :oldStatus ")
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("id", orderId)
        .setParameter("oldStatus", FlightChangeOrder.ORDER_STATUS_WAITING)
        .setParameter("newStatus", FlightChangeOrder.ORDER_STATUS_WORKING)
        .setParameter("lastUpdate", DateUtil.getCurDateTime())
        .setParameter("ticketer", username)
        .executeUpdate();
    if (retCode == 1) {
      OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
      log.setEnterpriseId(enterpriseId);
      log.setOrderId(orderId);
      log.setOperator(username);
      log.setContent("处理改签单");

      em.persist(log);
    }

    return retCode;
  }

  @Override
  public int cancelFlightChangeOrder(int enterpriseId, String username, int orderId,
      String remark) {
    int retCode = em.createQuery(
        "update FlightChangeOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate " +
            "where " +
            "o.id = :id and o.enterpriseId = :enterpriseId and (o.status = :oldStatus1 or o.status = :oldStatus2) ")
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("id", orderId)
        .setParameter("oldStatus1", ORDER_STATUS_WAITING)
        .setParameter("oldStatus2", ORDER_STATUS_WORKING)
        .setParameter("newStatus", ORDER_STATUS_CANCELED)
        .setParameter("lastUpdate", DateUtil.getCurDateTime())
        .executeUpdate();
    if (retCode == 1) {
      OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
      log.setEnterpriseId(enterpriseId);
      log.setOrderId(orderId);
      log.setOperator(username);
      log.setContent("取消改签单: " + remark);

      em.persist(log);
    }

    return retCode;
  }

  @Override
  public int reopenFlightChangeOrder(int enterpriseId, String username, int orderId) {
    int retCode = em.createQuery(
        "update FlightChangeOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate " +
            "where " +
            "o.id = :id and o.enterpriseId = :enterpriseId and o.status = :oldStatus ")
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("id", orderId)
        .setParameter("oldStatus", ORDER_STATUS_CANCELED)
        .setParameter("newStatus", ORDER_STATUS_WAITING)
        .setParameter("lastUpdate", DateUtil.getCurDateTime())
        .executeUpdate();
    if (retCode == 1) {
      OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
      log.setEnterpriseId(enterpriseId);
      log.setOrderId(orderId);
      log.setOperator(username);
      log.setContent("重新打开改签单");

      em.persist(log);
    }

    return retCode;
  }

  @Override
  public int finishFlightChangeOrder(int enterpriseId, String username, int orderId, String pnrNo,
      String ticketNo) {
    int retCode = em.createQuery(
            "update FlightChangeOrder o set o.status = :newStatus, o.newPnrNo = :pnrNo, o.newTicketNo = :ticketNo, " +
                    "o.lastUpdate = :lastUpdate " +
                    "where  o.id = :id and o.enterpriseId = :enterpriseId and o.status = :oldStatus ")
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("id", orderId)
            .setParameter("oldStatus", ORDER_STATUS_WORKING)
            .setParameter("newStatus", ORDER_STATUS_FINISHED)
            .setParameter("lastUpdate", DateUtil.getCurDateTime())
            .setParameter("pnrNo", pnrNo)
            .setParameter("ticketNo", ticketNo)
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("operate failed.");
    }
    OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
    log.setEnterpriseId(enterpriseId);
    log.setOrderId(orderId);
    log.setOperator(username);
    log.setContent("改签完成（" + pnrNo + ", " + ticketNo + ").");

    em.persist(log);

    return ORDER_STATUS_FINISHED;
  }

  @Override
  public int updateSupplier(int enterpriseId, String username, int orderId, Supplier supplier) {
    int retCode = em.createQuery("update FlightChangeOrder o set " +
        "o.supplier = :supplier " +
        "where o.id = :id and o.enterpriseId = :enterpriseId and o.status = :status")
        .setParameter("id", orderId)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("status", ORDER_STATUS_WORKING)
        .setParameter("supplier", supplier)
        .executeUpdate();

    if (retCode == 1) {
      OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
      log.setEnterpriseId(enterpriseId);
      log.setOrderId(orderId);
      log.setOperator(username);
      log.setContent("供应商更改为： " + supplier.getName());
      em.persist(log);
    } else {
      throw new RuntimeException("rollback");
    }

    return retCode;
  }

  @Override
  public int updatePaymentMethod(int enterpriseId, String username, int orderId, PaymentMethod o) {
    int retCode = em.createQuery(
        "update FlightChangeOrder o set o.paymentMethod = :paymentMethod, o.lastUpdate = :lastUpdate "
            +
            "where o.id = :id and o.enterpriseId = :enterpriseId and o.status = :status")
        .setParameter("id", orderId)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("paymentMethod", o)
        .setParameter("lastUpdate", DateUtil.getCurDateTime())
        .setParameter("status", ORDER_STATUS_WORKING)
        .executeUpdate();

    if (retCode != 1) {
      throw new RuntimeException("Update failed");
    }

    OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
    log.setEnterpriseId(enterpriseId);
    log.setOrderId(orderId);
    log.setOperator(username);

    String memo = "支付方式更改为：" + o.getName();
    log.setContent(memo);

    em.persist(log);

    return retCode;
  }

  @Override
  public int updateChangeOrderRemark(int enterpriseId, String username, int orderId,
      String remark) {
    int retCode = em.createQuery("update FlightChangeOrder o set " +
        "o.remark = :remark " +
        "where o.id = :id and o.enterpriseId = :enterpriseId")
        .setParameter("id", orderId)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("remark", remark)
        .executeUpdate();

    if (retCode == 1) {
      OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
      log.setEnterpriseId(enterpriseId);
      log.setOrderId(orderId);
      log.setOperator(username);
      log.setContent("备注修改为：" + remark);

      em.persist(log);
    }

    return retCode;
  }

  /**
   * 修改改签的票号
   * @param enterpriseId 企业id
   * @param username 用户名
   * @param orderId 订单id
   * @param balanceCode 结算码
   * @param ticketNo 10位票号
   */
  @Override
  public int updateChangeOrderTicketNo(int enterpriseId, String username, int orderId,
      String balanceCode, String ticketNo) {
    int retCode = em.createQuery("update FlightChangeOrder o set " +
        "o.balanceCode = :balanceCode, o.ticketNo = :ticketNo " +
        "where o.id = :id and o.enterpriseId = :enterpriseId")
        .setParameter("id", orderId)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("balanceCode", balanceCode)
        .setParameter("ticketNo", ticketNo)
        .executeUpdate();

    if (retCode == 1) {
      OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
      log.setEnterpriseId(enterpriseId);
      log.setOrderId(orderId);
      log.setOperator(username);
      log.setContent("改签票号修改为：" + balanceCode + "-" + ticketNo);

      em.persist(log);
    }

    return retCode;
  }

  @Override
  public void updateChangeOrderNewPnrNo(int enterpriseId, String username, int orderId, String newPnrNo) {
    int retCode = em.createQuery("update FlightChangeOrder o set " +
            "o.newPnrNo = :pnrNo " +
            "where o.id = :id and o.enterpriseId = :enterpriseId")
            .setParameter("id", orderId)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("pnrNo", newPnrNo)
            .executeUpdate();

    if (retCode == 1) {
      OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
      log.setEnterpriseId(enterpriseId);
      log.setOrderId(orderId);
      log.setOperator(username);
      log.setContent("新编码变更为：" + newPnrNo);

      em.persist(log);
    }

  }

  @Override
  public int updateChangeOrderPrice(int enterpriseId, String username, int id,
      double airChangeCharge, double serviceCharge) {
    int retCode = em.createQuery("update FlightChangeOrder o set " +
        "o.airChangeCharge = :airChangeCharge, o.serviceCharge = :serviceCharge, o.lastUpdate = :lastUpdate "
        +
        "where o.id = :id and o.enterpriseId = :enterpriseId and o.status = :status")
        .setParameter("id", id)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("status", ORDER_STATUS_WORKING)
        .setParameter("airChangeCharge", airChangeCharge)
        .setParameter("serviceCharge", serviceCharge)
        .setParameter("lastUpdate", DateUtil.getCurDateTime())
        .executeUpdate();

    if (retCode != 1) {
      throw new RuntimeException("Update failed");
    }

    OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
    log.setEnterpriseId(enterpriseId);
    log.setOrderId(id);
    log.setOperator(username);

    String memo = "修改订单价格(改签费：" + airChangeCharge + ", 服务费：" + serviceCharge + ")";
    log.setContent(memo);

    em.persist(log);

    return retCode;
  }

  /**
   * 修改改签订单的航班信息
   */
  @Override
  public int updateChangeOrderFlightInfo(final int enterpriseId, final String username,
      final int id, final FlightChangeOrderDetail newDetail) {
    FlightChangeOrder orderInfo = em.find(FlightChangeOrder.class, id);
    if (orderInfo == null || orderInfo.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("改签订单不存在(ChangeOrder is not existed).");
    }

    em.refresh(orderInfo);
    if (orderInfo.getStatus() == ORDER_STATUS_FINISHED) {
      throw new RuntimeException("改签单已完成(ChangeOrder is done).");
    }

    FlightChangeOrderDetail detail = em.find(FlightChangeOrderDetail.class, newDetail.getId());
    if (detail == null || detail.getOrder().getId() != id) {
      throw new RuntimeException("航班信息有误(FlightInfo is error).");
    }

    String logContent =
        detail.getFlight().getRouteDetail() + "修改为" + newDetail.getFlight().getRouteDetail();

    BeanUtils.copyProperties(newDetail.getFlight(), detail.getFlight());

    //更新数据库
    em.merge(detail);

    //记录日志
    OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
    log.setEnterpriseId(enterpriseId);
    log.setOrderId(id);
    log.setOperator(username);
    log.setContent(logContent);

    em.persist(log);

    return newDetail.getId();
  }

  @Override
  public int rollbackChangeOrderStatus(int enterpriseId, String username, int id,
      final String remark) {
    int retCode = 0;

    FlightChangeOrder o = em.find(FlightChangeOrder.class, id);
    if (o == null || o.getEnterpriseId() != enterpriseId) {
      throw new RuntimeException("FlightChangeOrder is not existed.");
    }

    if (o.getStatus() == ORDER_STATUS_FINISHED) {
      // 已完成 -> 处理中
      retCode = em.createQuery(
          "update FlightChangeOrder o set o.status = :newStatus, o.lastUpdate = :lastUpdate " +
              "where o.id = :id and o.enterpriseId = :enterpriseId and o.status = :oldStatus")
          .setParameter("id", id)
          .setParameter("enterpriseId", enterpriseId)
          .setParameter("oldStatus", ORDER_STATUS_FINISHED)
          .setParameter("newStatus", ORDER_STATUS_WORKING)
          .setParameter("lastUpdate", DateUtil.getCurDateTime())
          .executeUpdate();

      if (retCode != 1) {
        throw new RuntimeException("can not update change order status");
      }

      String memo = "状态回滚为处理中: " + remark;
      OperationLog log = createFlightChangeOrderLog(enterpriseId, username, id, memo);

      em.persist(log);

    } else {
      throw new RuntimeException("FlightChangeOrder status can not be rollback.");
    }

    return retCode;
  }

  @Override
  public List<FlightChangeOrder> searchUnpaidOrders(int max) {
    return em.createQuery("select o from FlightChangeOrder o " +
            "where o.status = :status " +
            "and o.createTime >= :createTime " +
            "and (o.payStatus is null or o.payStatus <> 2) order by o.id desc", FlightChangeOrder.class)
            .setParameter("status", ORDER_STATUS_FINISHED)
            .setParameter("createTime", getMinBeginDate())
            .setMaxResults(max)
            .getResultList();
  }

  @Override
  public void setOrderWrittenOff(int enterpriseId, String username, int id, String remark) {
    int retCode = em.createQuery("update FlightChangeOrder o set o.payStatus = 2 " +
        "where o.id = :id and o.enterpriseId = :enterpriseId and (o.payStatus is null or o.payStatus <> 2)")
        .setParameter("id", id)
        .setParameter("enterpriseId", enterpriseId)
        .executeUpdate();

    if (retCode == 1) {
      OperationLog log = createFlightChangeOrderLog(enterpriseId, username, id, "已销账：" + remark);

      em.persist(log);
    }

  }

  @Override
  public List<FlightChangeOrder> searchByFlightOrderNo(int enterpriseId,
      String orderNo) {
    return em.createQuery("select o from FlightChangeOrder o "
        + "where o.enterpriseId = :enterpriseId and o.orderNo = :orderNo order by o.ticketNo", FlightChangeOrder.class)
        .setParameter("enterpriseId", enterpriseId)
        .setParameter("orderNo", orderNo)
        .getResultList();

  }

  @Override
  public List<FlightChangeOrder> searchChangeOrdersNeedPriceCheck(int enterpriseId, Date startDate) {
    return em.createQuery("select o from FlightChangeOrder o "
            + "where o.enterpriseId = :enterpriseId and (o.status = :status1) and o.createTime >= :createDate "
            + "order by o.id", FlightChangeOrder.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("status1", ORDER_STATUS_WAITING)
            .setParameter("createDate", startDate)
            .getResultList();
  }

  @Override
  public List<FlightChangeOrder> searchChangeOrdersNeedRefreshDetr(final int enterpriseId, final int max) {
    final Date startDate = DateUtil.addDays(DateUtil.getCurDateTime(), -365);

    return em.createQuery("select o from FlightChangeOrder o "
            + "where o.enterpriseId = :enterpriseId " +
            "and o.status = :status " +
            "and (o.detrRefreshStatus is null or o.detrRefreshStatus = 0) " +
            "and o.createTime >= :createDate " +
            "order by o.id", FlightChangeOrder.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("status", ORDER_STATUS_FINISHED)
            .setParameter("createDate", startDate)
            .setMaxResults(max)
            .getResultList();
  }

  @Override
  public List<FlightChangeOrder> searchChangeOrdersDetrFinished(final int enterpriseId, final int max) {
    return em.createQuery("select o from FlightChangeOrder o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.detrRefreshStatus = 1 " +
            "order by o.id desc", FlightChangeOrder.class)
            .setParameter("enterpriseId", enterpriseId)
            .setMaxResults(max)
            .getResultList();
  }

  @Override
  public void appendFlightChangeOrderLog(int enterpriseId, int orderId, String username, String content) {
    OperationLog log = createFlightChangeOrderLog(enterpriseId, username, orderId, content);

    em.persist(log);

  }

  @Override
  public List<FlightChangeOrder> searchMobileIsNull(int enterpriseId) {
    final Date startDate = DateUtil.getYesterday();
    return em.createQuery("select o from FlightChangeOrder o "
            + "where o.enterpriseId = :enterpriseId " +
            "and o.mobile is null " +
            "and o.createTime >= :createDate "
            + "order by o.id", FlightChangeOrder.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("createDate", startDate)
            .getResultList();
  }

  @Override
  public void updateChangeOrderMobile(int enterpriseId, String username, int orderId, String mobile) {
    int retCode = em.createQuery("update FlightChangeOrder o set " +
            "o.mobile = :mobile " +
            "where o.id = :id and o.enterpriseId = :enterpriseId")
            .setParameter("id", orderId)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("mobile", mobile)
            .executeUpdate();

    if (retCode == 1) {
      OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
      log.setEnterpriseId(enterpriseId);
      log.setOrderId(orderId);
      log.setOperator(username);
      log.setContent("乘机人电话：" + mobile);

      em.persist(log);
    }

  }

  @Override
  public void updateChangeOrderDetrStatus(int enterpriseId, String username, int orderId, int status) {
    int retCode = em.createQuery("update FlightChangeOrder o " +
            "set " +
            "o.detrRefreshStatus = :status, o.detrRefreshTime = :refreshTime " +
            "where o.id = :id and o.enterpriseId = :enterpriseId")
            .setParameter("id", orderId)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("status", status)
            .setParameter("refreshTime", DateUtil.getCurDateTime())
            .executeUpdate();
    if (retCode != 1) {
      throw new RuntimeException("updateChangeOrderDetrStatus failed");
    }

    FlightChangeOrder orderInfo = em.find(FlightChangeOrder.class, orderId);
    em.createQuery("update FlightOrder o set o.detrRefreshStatus = :status " +
            "where o.enterpriseId = :enterpriseId and o.orderNo = :orderNo")
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("orderNo", orderInfo.getOrderNo())
            .setParameter("status", 1)
            .executeUpdate();

    OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
    log.setEnterpriseId(enterpriseId);
    log.setOrderId(orderId);
    log.setOperator(username);
    log.setContent("更新detr信息(" + status + ").");

    em.persist(log);

  }

  @Override
  public List<FlightChangeOrder> searchChangeOrdersNeedRecheckDetr(final int enterpriseId, final int max) {
    final Date lastRefreshTime = DateUtil.addMinutes(DateUtil.getCurDateTime(), -120);
    return em.createQuery("select o from FlightChangeOrder o "
            + "where o.enterpriseId = :enterpriseId " +
            "and o.status = :status " +
            "and o.detrRefreshStatus = 1 " +
            "and o.detrRefreshTime < :lastRefreshTime " +
            "order by o.id", FlightChangeOrder.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("status", ORDER_STATUS_FINISHED)
            .setParameter("lastRefreshTime", lastRefreshTime)
            .setMaxResults(max)
            .getResultList();

  }

  @Override
  public List<FlightChangeOrder> searchChangeOrdersNeedRefreshPnr(int enterpriseId, int max) {
    final Date startDate = DateUtil.getYesterday();
    return em.createQuery("select o from FlightChangeOrder o " +
            "where o.enterpriseId = :enterpriseId " +
            "and o.createTime >= :createDate " +
            "and o.pnrRefreshStatus is null " +
            "order by o.id", FlightChangeOrder.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("createDate", startDate)
            .setMaxResults(max)
            .getResultList();
  }

  @Override
  public void updateChangeOrderRefreshPnrStatus(int enterpriseId, String username, int orderId) {
    int retCode = em.createQuery("update FlightChangeOrder o set " +
            "o.pnrRefreshStatus = :pnrStatus,  o.lastUpdate = :lastUpdate " +
            "where o.id = :id and o.enterpriseId = :enterpriseId")
            .setParameter("id", orderId)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("pnrStatus", 1)
            .setParameter("lastUpdate", DateUtil.getCurDateTime())
            .executeUpdate();

    if (retCode == 1) {
      OperationLog log = createFlightChangeOrderLog(enterpriseId, username, orderId,
              "改签完成后更新编码内容。");
      em.persist(log);
    }

  }

  @Override
  public void updateChangeOrderRefreshPnrStatusFailed(int enterpriseId, String username, int orderId, String remark) {
    int retCode = em.createQuery("update FlightChangeOrder o set " +
            "o.pnrRefreshStatus = :pnrStatus,  o.lastUpdate = :lastUpdate " +
            "where o.id = :id and o.enterpriseId = :enterpriseId")
            .setParameter("id", orderId)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("pnrStatus", 4)
            .setParameter("lastUpdate", DateUtil.getCurDateTime())
            .executeUpdate();

    if (retCode == 1) {
      OperationLog log = createFlightChangeOrderLog(enterpriseId, username, orderId,
              "改签完成后更新编码内容失败(" + remark + ").");
      em.persist(log);
    }

  }

  @Override
  public int saveChangeOrderAttachment(int enterpriseId, String username, int orderId, List<OrderAttachment> attachments) {
    return saveOrderAttachment(enterpriseId, username, ORDER_TYPE_FLIGHT_CHANGE, orderId, attachments);
  }

  @Override
  public List<OrderAttachment> searchAttachments(int enterpriseId, int orderId) {
    return searchAttachments(enterpriseId, ORDER_TYPE_FLIGHT_CHANGE, orderId);
  }

  @Override
  public List<FlightChangeOrder> searchSupplierIsNull(int enterpriseId) {
    final Date startDate = DateUtil.addDays(DateUtil.getYesterday(), -90);
    return em.createQuery("select o from FlightChangeOrder o "
            + "where o.enterpriseId = :enterpriseId " +
            "and o.supplier is null " +
            "and o.createTime >= :createDate "
            + "order by o.id desc", FlightChangeOrder.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("createDate", startDate)
            .setMaxResults(50)
            .getResultList();
  }

  @Override
  public int updateChangeOrderSupplier(int enterpriseId, String username, int id, Supplier supplier, PaymentMethod pm) {
    int retCode = em.createQuery("update FlightChangeOrder o set " +
            "o.supplier = :supplier, o.paymentMethod = :pm " +
            "where o.id = :id and o.enterpriseId = :enterpriseId and o.supplier is null and o.paymentMethod is null ")
            .setParameter("id", id)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("supplier", supplier)
            .setParameter("pm", pm)
            .executeUpdate();

    if (retCode == 1) {
      OperationLog log = OperationLogFactory.createFlightChangeOrderOperationLog();
      log.setEnterpriseId(enterpriseId);
      log.setOrderId(id);
      log.setOperator(username);
      log.setContent("修改供应商为 " + supplier.getName() + ", 支出方式为 " + pm.getName());

      em.persist(log);
    }

    return retCode;
  }

  @Override
  public int updateExternalOrderNo(int enterpriseId, String username, int orderId, String externalOrderNo, String remark) {
    int retCode = em.createQuery("update FlightChangeOrder o set " +
                    "o.externalOrderNo = :orderNo, o.lastUpdate = :lastUpdate " +
                    "where o.id = :id and o.enterpriseId = :enterpriseId")
            .setParameter("id", orderId)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("orderNo", externalOrderNo)
            .setParameter("lastUpdate", DateUtil.getCurDateTime())
            .executeUpdate();
    if (retCode == 1) {
      appendFlightChangeOrderLog(enterpriseId, orderId, username, remark);
    }

    return retCode;
  }

  @Override
  public List<FlightChangeOrder> searchWaiting(int enterpriseId, Date startDate) {
    return em.createQuery("select o from FlightChangeOrder o "
                    + "where o.enterpriseId = :enterpriseId " +
                    "and (o.status = :status1 or o.status = :status2) " +
                    "and o.createTime >= :createDate "
                    + "order by o.id desc", FlightChangeOrder.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("createDate", startDate)
            .setParameter("status1", FlightChangeOrder.ORDER_STATUS_WAITING)
            .setParameter("status2", ORDER_STATUS_WORKING)
            .getResultList();
  }

  @Override
  public List<FlightChangeOrder> searchChangeOrderByPnrNo(int enterpriseId, String pnrNo) {
    return em.createQuery("select o from FlightChangeOrder o " +
                    "where o.enterpriseId = :enterpriseId " +
                    "and o.newPnrNo = :pnrNo and o.status <> :status order by o.id desc", FlightChangeOrder.class)
            .setParameter("enterpriseId", enterpriseId)
            .setParameter("status", ORDER_STATUS_CANCELED)
            .setParameter("pnrNo", pnrNo)
            .setMaxResults(10)
            .getResultList();
  }
}
